package com.zhiwei.msf.infra.oauth.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.MacSigner;
import org.springframework.security.jwt.crypto.sign.Signer;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.JsonParser;
import org.springframework.security.oauth2.common.util.JsonParserFactory;
import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhiwei_yang
 * @since 2019-5-9
 */
@Configuration
public class JwtConfig {

    /**
     * 源码：org.springframework.security.oauth2.provider.token.DefaultTokenServices#createAccessToken
     * 原理：TokenEnhancer 自定义实现取代原始的UUID Token生成策略,JWT可携带用户状态信息，注意不要携带敏感数据
     * 作用：在默认的UUID Token进一步转换成JWT,使Token协议携带一定的业务数据
     *
     * @return
     */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {

        JsonParser objectMapper = JsonParserFactory.create();
        String verifierKey = new RandomValueStringGenerator().generate();
        Signer signer = new MacSigner(verifierKey);

        //重写默认JWT方法，防止敏感数据泄露: 这里存放用户名及有效时间点
        //案例：eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX25hbWUiOiJhZG1pbiIsImV4cGlyZV90aW1lIjoxNTgyNzM0Mzc1NDIwfQ.XgVjHp4QrPLn-5sqpH7OT22sgl3139W3mHE_FDzNSgQ
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter() {

            @Override
            public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
                DefaultOAuth2AccessToken defaultOAuth2AccessToken = new DefaultOAuth2AccessToken(accessToken);
                final Map<String, Object> additionalInformation = new HashMap<>();
                if(null != authentication.getUserAuthentication()){
                    additionalInformation.put("user_name", authentication.getUserAuthentication().getName());
                }else{
                    additionalInformation.put("user_name", authentication.getPrincipal());
                }
                additionalInformation.put("expire_time", accessToken.getExpiration());
                defaultOAuth2AccessToken.setAdditionalInformation(additionalInformation);
                defaultOAuth2AccessToken.setValue(JwtHelper.encode(objectMapper.formatMap(additionalInformation), signer).getEncoded());
                return defaultOAuth2AccessToken;
            }

        };
        //指定JWT数据签名秘钥
        accessTokenConverter.setSigningKey("clientSecret");
        return accessTokenConverter;
    }
}